/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package cz.dusa.switco;

import java.util.ArrayList;
import java.util.List;

/**
 * Singleton class holding all trees in the schedule
 * @author vdusa
 */
public class Forest {
    static long lastTreeId = 1;
    static Forest instance = null;
    List<EqualityTree> equalityTrees = new ArrayList<EqualityTree>();

    private Forest() {};

    /**
     * @return instance of the singleton class Forest
     */
    public static Forest getInstance(){
        if(instance == null){
            instance = new Forest();
        }
        return instance;
    }

    /**
     * Adds a new tree into the list
     * @param tree is a new tree
     */
    public void plantTree(EqualityTree tree){        
        equalityTrees.add(tree);
        tree.setId(lastTreeId);
        lastTreeId++;
    }

    /**
     * Removes the given tree from the list
     * @param tree to be removed
     */
    public void chopTree(EqualityTree tree){
        equalityTrees.remove(tree);
    }

    /**
     * @param id of the searched task.
     * @return Task with given id.
     */
    public Task getTask(Long id){
        for(EqualityTree tree: equalityTrees){
            for(Task task: tree.getTasksHolder().getTasks()){
                if(task.getId().equals(id)){
                    return task;
                }
            }
        }

        return null;
    }

    /**
     * @return if the whole Forest is optimal in the schedule. It means, that 
     * each tree in the forest is active and on time and no precedence is violated.
     */
    public boolean isOptimal(){
        for(EqualityTree tree: equalityTrees){
            if(!(tree.isActive() && tree.isOnTime())){
                //there is a tree, that is not active or on time
                return  false;
            }
            for(Task task: tree.getTasksHolder().getTasks()){
                for(Precedence predecessor: task.getPredecessors()){
                    boolean isViolated = predecessor.isViolated();
                    if(isViolated){
                        //violated precedence found
                        return false;
                    }
                }
                for(Precedence successor: task.getSuccessors()){
                    boolean isViolated = successor.isViolated();
                    if(isViolated){
                        //violated precedence found
                        return false;
                    }
                }
            }
        }
        
        //all trees are active and on time
        return true;
    }

    /**
     * @return true if no precedences in Schedule is not violated. If any precedence
     * is violated, true will be returned.
     */
    public boolean isFeasible(){
        for(EqualityTree tree: equalityTrees){
            for(Task task: tree.getTasksHolder().getTasks()){
                for(Precedence precedence: task.getSuccessors()){
                    if(precedence.isViolated()){
                        return false;
                    }
                }
            }
        }

        //no precedence is violated
        return true;
    }
    
    /**
     * Removes all trees from the forest.
     */
    public void clear(){
        equalityTrees.clear();
        lastTreeId = 0;
    }

    /**
     * @return count of trees in the forest
     */
    public int size(){
        return equalityTrees.size();
    }

    @Override
    public String toString(){
        String output = "";

        for(EqualityTree tree: equalityTrees){
            output += (output.equals("")?"":"\n") + "tree " + tree.getId();
            
            String precedences = "";
            for(Precedence precedence: tree.getTreePrecedences()){
                precedences += (precedences.equals("")?"":";") + precedence;
            }
            if (!precedences.equals("")){
                output += " {" + precedences + "}";
            }
            if(tree.getTasksHolder().getTasks().isEmpty()) {output += "\n";}
            for(Task task: tree.getTasksHolder().getTasks()){
                output += ("\n" + task.getId() + ", start:" + task.getStart() + ", treeShift:" + task.getTreeShift());
            }
        }
        return output;
    }

    public List<Task> getTasks() {
        List<Task> tasks = new ArrayList<Task>();

        for(EqualityTree tree: equalityTrees){
            tasks.addAll(tree.getTasksHolder().getTasks());
        }
        
        return tasks;
    }

    public List<Precedence> getPrecedences(){
        List<Task> tasks = getTasks();
        List<Precedence> precedences = new ArrayList<Precedence>();

        for(Task t: tasks){
            for(Precedence p: t.getSuccessors()){
                precedences.add(p);
            }
        }

        return precedences;
    }
}
